//
// Created by LiuYou on 2021/10/20.
//

#include <iostream>
#include <unistd.h>
#include <cstring>


static const int LEFT = 30000000;
static const int RIGHT = 30000200;


/**
 * @brief
 * @details 用 201 个子进程来计算这 201 个待计算的任务。
 * 那就是每次产生一个待计算的 i 值, 我就马上 fork(); 把这个 i 扔给子进程。
 *
 * <p>当前这个版本在Ubuntu上测试结果是: CPU的两个核同时飙升, 但是最高值为 40% 到 60% 之间。
 * 没有像上一个版本那样, 直接飙满CPU的一个核。
 *
 * <p> shell: ps axf

    150308 pts/1    S      0:00  \_ ./a.out
    150309 pts/1    S      0:00  \_ ./a.out
    150310 pts/1    S      0:00  \_ ./a.out
    150311 pts/1    S      0:00  \_ ./a.out
    150312 pts/1    S      0:00  \_ ./a.out
    150313 pts/1    S      0:00  \_ ./a.out
    150314 pts/1    S      0:00  \_ ./a.out
    150315 pts/1    S      0:00  \_ ./a.out

 * <p>如果当前进程是像上面那样写( \_ ./a.out )的话, 那就表明当前进程的父进程是 init 进程。
 *
 *

 149234 pts/1    Ss     0:00      \_ bash
 150831 pts/1    S+     0:00      |   \_ ./ProcessBasic-fork2-primer3
 150832 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150833 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150834 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150835 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150836 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150837 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150838 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150839 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150840 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150841 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150842 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150843 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150844 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150845 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150846 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150847 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150848 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150849 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 150850 pts/1    Z+     0:00      |       \_ [ProcessBasic-fo] <defunct>
 ...

 * <p>当前父进程 150831 pts/1    S+     0:00      |   \_ ./ProcessBasic-fork2-primer3 的进程状态是 S+ , 即可中断的
 * 睡眠态。而已经退出的这 201 个子进程的进程状态是 Z+ , 即僵尸态。 defunct: 僵尸进程。
 *
 * 父进程因为没有为子进程收尸, 所以子进程变为了僵尸进程。
 *
 * 僵尸进程是非常常见的, 是很正常的。但是僵尸进程应该是一闪即逝, 父进程为它收尸了; 或者当前进程关系当中会有几个僵尸进程,
 * 然后过了三五秒钟再查看进程关系, 发现还是有几个僵尸进程, 但是换了一批, 这说明要么当前的操作系统比较忙, 要么就是父进程比较忙没有来的及收尸,
 * 父进程可能过一段时间再来收尸。
 *
 * <p>僵尸进程大量存在有什么影响? 僵尸进程大量存在其实占不了多少内存, 一个僵尸进程就是一个结构体: 内核为每个终止子进程保存了
 * 一定量的信息, 所以当终止的子进程的父进程调用wait或waitpid时, 可以获得这些信息。这些信息至少包括: 终止子进程的PID,
 * 终止子进程的终止状态以及这个终止子进程使用的CPU时间总量。
 *
 * 其实僵尸态的进程是所占资源非常小的一个状态, 不会争抢很多资源, 但是僵尸态的进程占用着一个非常宝贵的资源: PID(进程号)。
 *
 * <p>在父进程sleep(100);后, 父进程退出。而这些僵尸进程同时变为孤儿进程, 会由 init 进程接管, 由 init进程 负责收尸。
 *
 * <p>当前的这个程序还差一个模块, 收尸环节。
 * 应该是父进程创建完子进程, 子进程在干活, 父进程干其它话, 然后父进程要负责为子进程收尸, 收尸最主要的有两件事做:
 * 1. 是否关系子进程的退出状态, 如果关心的话, 应该从僵尸进程中把子进程的退出状态取过来。
 * 2. 释放子进程的PID。这个资源非常宝贵, 这也是大量僵尸存在的时候不好的地方。
 *
 *
 * <p>fork();函数现在被设计为了COW(写时拷贝技术)。父子进程对数据都是只读不写的, 而父子进程如果要修改数据的话,
 * 就会在真实的内存中拷贝一份, 然后修改它。哪个进程改哪个进程就拷贝。
 *
 * 所以fork();现在的设计是将vfork();函数的优点吸取进来了。而vfork();函数现在是已经弃用的函数。
 *
 * @param argc
 * @param argv
 * @return
 */
int main(int argc, char** argv) {
    int mark{};
    for (int i = LEFT; i < RIGHT; ++i) {

        pid_t pid = fork();
        if (pid < 0) {
            perror( "fork()" );
            exit( 1 );
        }
        if (pid == 0) {
            mark = 1;
            for (int j = 2; j < i / 2; ++j) {
                if (i % j == 0) {
                    mark = 0;
                    break;
                }
            }
            if (mark == 1) {
                printf( "%d 是一个质数。\n", i );
            }
//            sleep( 100 );
            exit( 0 );
        }

    }

    sleep( 100 );
    return 0;
}
